#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "window.h"
#include "event_queue.h"
#include "_listener.h"
#include "listener.h"
#include "listbox.h"

#ifndef _LISTENER_INIT_
#define _LISTENER_INIT_

#define __E(fmt, args...) fprintf(stderr, "%s [%d]: ERROR: " fmt, __FILE__, __LINE__, ## args)
#define __W(fmt, args...) fprintf(stderr, "%s [%d]: WARNING: " fmt, __FILE__, __LINE__, ## args)

#define false               0
#define true                1

#define MAX_NUMBER_LISTENERS    100

static listener listeners[MAX_NUMBER_LISTENERS];
static int lsId = 0;
static int event_handler_started = 0;
static davint_event_queue_t *queue = NULL;
static pthread_t listener_eventHandlerId;

#endif

davint_event_queue_t *listener_eventQueue_request() {
	if (event_handler_started)
	    return queue;
	else
		return LISTENER_FAILURE;
}

int listener_eventHandler() {
    queue = davint_event_init_queue();
    if (queue == NULL)
        return LISTBOX_FAILURE;
    while (1) {
        event e, *e_p;
        e_p = &e;
        int size;
        int time;
        int error;

        if ((error = davint_event_dequeue(queue, &e_p, &size, &time)) != E_OK) {
            if (error != E_EMPTY_QUEUE) {
                __E("Falha no eventHandler\n");
                return LISTENER_FAILURE;
            }
        } else {
            listener_eventTrigger(e);
        }
        usleep(10000);
    }
}

int listener_eventHandler_start() {

	if (!event_handler_started) {
		pthread_create(&listener_eventHandlerId, NULL, (void *) listener_eventHandler, NULL);
		event_handler_started = 1;
	}

	return LISTENER_SUCCESS;
}

int listener_create(listener_type event, void *pFunction) {
    if (lsId <= MAX_NUMBER_LISTENERS) {
        listeners[lsId].type = event;
        listeners[lsId].function = pFunction;
        listeners[lsId].windowId = -1;
        listeners[lsId].id = lsId;
        listeners[lsId].initialized = true;

        return lsId++;
    } else {
        __E("Nao foi possivel criar o listener. Numero maximo.\n");
        return LISTENER_FAILURE;
    }
}

signed int listener_destroy(signed int listenerId) {
    if (!listeners[listenerId].initialized) {
        __E("Listener nao pode ser destruido: listener nao foi criado.");
        return LISTENER_FAILURE;
    }

    listeners[listenerId].type = -1;
    listeners[listenerId].function = NULL;

    listener_delFromWindow(listenerId);
    listeners[listenerId].initialized = 0;
    return LISTENER_SUCCESS;
}

int listener_addToWindow(int listenerId, int listenerId_next, int windowId) {
    if (listeners[listenerId_next].windowId == -1) {
        listeners[listenerId_next].next = listeners[listenerId].next;
        listeners[listenerId].next = &listeners[listenerId_next];
        listeners[listenerId_next].previous = &listeners[listenerId];
        listeners[listenerId_next].next->previous = &listeners[listenerId_next];
        listeners[listenerId_next].windowId = windowId;
        return LISTENER_SUCCESS;
    } else {
        __E("Ja existe uma tela associada ao listener.\n");
        return LISTENER_FAILURE;
    }
}

signed int listener_delFromWindow(signed int listenerId) {
    if (!listeners[listenerId].initialized) {
        __E("Listener nao criado.\n");
        return LISTENER_FAILURE;
    }

    if (listeners[listenerId].winp == NULL) {
        return LISTENER_SUCCESS;
    }

    if (listeners[listenerId].next == &listeners[listenerId]) {
        listeners[listenerId].winp->firstListener = -1;
        listeners[listenerId].winp->actualListener = -1;
    } else {
        if (listeners[listenerId].winp->actualListener == listenerId) {
            listeners[listenerId].winp->actualListener = listeners[listeners[listenerId].winp->actualListener].previous->id;
        } else if (listeners[listenerId].winp->firstListener == listenerId) {
            listeners[listenerId].winp->firstListener = listeners[listeners[listenerId].winp->firstListener].next->id;
        }

        listeners[listenerId].previous->next = listeners[listenerId].next;
        listeners[listenerId].next->previous = listeners[listenerId].previous;
    }

    listeners[listenerId].previous = &listeners[listenerId];
    listeners[listenerId].next = &listeners[listenerId];
    listeners[listenerId].windowId = -1;
    listeners[listenerId].winp = NULL;

    return LISTENER_SUCCESS;
}

int listener_eventTrigger(event e) {
    if (e.type == EVENT_NULL) {
        __E("Evento nao registrado.\n");
        return LISTENER_FAILURE;
    }
    int tmp;
    int window_enable = window_getEnable();
    if (window_enable != -1) {
        tmp = window_findListenerId(window_enable, e.type);
        if (tmp != WINDOW_FAILURE) {
            listeners[tmp].function(e.paramp, e.paramsize);
            if (e.paramsize > 0 && e.paramp != NULL) {
                free(e.paramp);
            }
			/* Atualizar tela ativa apos tratamento do evento */\
            window_refresh();
        }
    } else return LISTENER_FAILURE;
}

event_type listener_getEventType(int listenerId) {
    return listeners[listenerId].type;
}

int listener_next(int listenerId) {
    if (listeners[listenerId].initialized) {
        return listeners[listenerId].next->id;
    }
}
